MapManager = {}


function MapManager:initialize()

	self.maps = {}
	self.rng = mwc()
	self.prefix = "m_"
	self.path = MOAIPathFinder.new()
	self.ja = 0
	
	

end

function MapManager:get_current_map()

	return self.maps[Game.current_map]

end

function MapManager:get_current_col_grid()
	if self.maps[Game.current_map] then
		if self.maps[Game.current_map].col_grid then
			return self.maps[Game.current_map].col_grid
		else
			
		end
	else
	
		ThreadManager:wait_thread( #ThreadManager.threads )
		return self.maps[Game.current_map].col_grid
		
	end
	
end

function MapManager:save_map( map_number )

	local cereal = MOAISerializer.new()
	local fs = MOAIFileSystem

	
	local map_dir = fs:getWorkingDirectory()..[[maps/]]
	
	print("MAP MANAGER save_map map dir : ", map_dir)
	
	fs:affirmPath(map_dir)
	
	local rp = fs:getAbsoluteDirectoryPath(map_dir)
	rp = rp..[[maps/]]

	print("MAP MANAGER save_map rp : ", rp)
	local files = MOAIFileSystem:listFiles()
	
	local prefix = self.prefix
	
	local file_num = 1
	
	local pc = prefix:len()
	
	for i = 1, #files do
		print("MAP MANAGER files .." ..files[i])
		if files[i]:sub(1, pc) == prefix then
			
			file_num = file_num + 1
		end
	end
	
	
	
	local fn = prefix..USER_NAME.."_"..file_num
	print("MAP MANAGER filename fn : ".. fn)
	
	local fp = fn
	
	print("MAP MANAGER filepath fp : ", fp)
	
	local map = self.maps[map_number]
	local saving_map = {}
	--local gs = MOAISerializer:serializeToString(map.grid)
	
	
	saving_map.height = map.height
	saving_map.width = map.width
	saving_map.t_wid = map.t_wid
	saving_map.t_hgh = map.t_hgh
	
	cereal:serialize(saving_map)
	cereal:serialize(map.grid)
	cereal:serialize(map.col_grid)
	
	if not fs:checkFileExists(fp) then
	
		
		cereal:exportToFile(fp)
		
	
	else
		fs:deleteFile(fp)
		cereal:exportToFile(fp)
	end



end



function MapManager:load_map( user_name, map_number, pos )

	local prefix = self.prefix
	local file_name =  prefix .. user_name .. "_" .. map_number
	local iter = #self.maps+1
	local gd, cg
	--print(unpack(MOAIFileSystem:listFiles()))
	local ft = MOAIFileSystem.listFiles()
	local fc = false
	
	for i = 1, #ft do
	
		if ft[i] == file_name then fc = true end
	
	end
	
	if fc == true then
		self.maps[iter], gd, cg = dofile(file_name)
	
		self.maps[iter].grid = gd
		
		self.maps[iter].col_grid = cg
	else
		print("ERROR: no such file")
		
		return
	end
	--local tg = self.maps[iter].grid
	
	--self.maps[iter].grid = loadstring(tg, '')
	
	
	
	Game.current_map = iter
	
	self.maps[iter].viewport = MOAIViewport.new()
	self.maps[iter].viewport:setSize( 
		SCREEN_RESOLUTION_X-SCREEN_RESOLUTION_X*0.125, 
		SCREEN_RESOLUTION_Y-SCREEN_RESOLUTION_Y*0.125)
	self.maps[iter].viewport:setScale ( WORLD_RESOLUTION_X, -WORLD_RESOLUTION_Y )
	self.maps[iter].viewport:setOffset(-0.885, 0.885)
	self.maps[iter].layer = MOAILayer2D.new()
	self.maps[iter].layer:setViewport(self.maps[iter].viewport)
	self.maps[iter].layer:setCamera(Game.camera)
	
	Game:render_layer( self.maps[iter].layer, 2, 2)
	
	--[[ -- render the layer
	local renderTable = MOAIRenderMgr.getRenderTable()
	
	if pos then 
		table.insert ( renderTable, pos, self.maps[iter].layer )
	else
		table.insert ( renderTable, self.maps[iter].layer )
	end

	MOAIRenderMgr.setRenderTable ( renderTable )
	
	]]
	
	print("MAP MANAGER load_map Game.current_map\n" .. Game.current_map)
	
	--Game:setupLayers()	
	Game:space_bg()
	Game:populateBackground()

end

function MapManager:list_map_files()

	local files = MOAIFileSystem:listFiles()
	local pre_len = self.prefix:len()
	local map_names = {}
	
	for i = 1, #files do
		
		if files[i]:sub(1, pre_len) == self.prefix then
			map_names[#map_names+1] = files[i]
		end
	
	end
	
	return map_names

end

function MapManager:set_bot_hatch()

	local map = self:get_current_col_map()
	
	local hatches = 4
	
	for i = 1, hatches do
	
		
	
	end

end

function MapManager:path_points(start_x, start_y, dest_x, dest_y)

	

end

function MapManager:quick_map( height, width, t_wid, t_hgh, algo, pos )
	
	self.qm = {}
	self.qm.height = height
	self.qm.width = width
	self.qm.t_wid = t_wid
	self.qm.t_hgh = t_hgh
	self.qm.algo = algo
	self.qm.pos = pos
	
	local zzz = self:map_thread ( )
	

	--self:path_update_grid ( self.maps[zzz] )
end

function MapManager:map_thread( )

	local m_thread = MOAICoroutine.new()
	
	m_thread:run(self.add_map, self )
	
	local iter2 = #ThreadManager.threads
	
	--[[
	while m_thread:isBusy() do
	
		coroutine.yield()
	end
	]]
	
	--MOAICoroutine.blockOnAction( m_thread )
	
	local iter = #self.maps
	
	return iter
	
end


function MapManager:add_map( height, width, t_wid, t_hgh, algo, pos )
	
	height = height or self.qm.height
	width = width or self.qm.width
	t_wid = t_wid or self.qm.t_wid
	t_hgh = t_hgh or self.qm.t_hgh
	algo = algo or self.qm.algo
	pos = pos or self.qm.pos
	
	print("MAP MANAGER add_map h, w, t_w, t_h, algo, pos ".. height, width, t_wid, t_hgh, algo, pos )
	
	local map = MOAIGrid.new ()
	map:setSize( height, width, t_wid, t_hgh )
	
	
	algos = {
	
		["cell_auto"] = 
			function (map, height, width, t_wid, t_hgh) 
				return self:new_cell_auto_map(map, height, width, t_wid, t_hgh) 
			end,
			
		["manual_grid"] =
			function(x)
				
				return self:toMOAIGrid(self.mg_cache)
			
			end,
	
	
	}
	
	
	local grid
	if algos[algo] then
		grid = algos[algo](map, height, width, t_wid, t_hgh)
	else
		print("ERROR: no such algorithm")
	end
	
	local col_grid = self:collision_grid(grid)
	local iter = #self.maps+1
	
	self.maps[iter] = {}
	self.maps[iter].grid = grid
	self.maps[iter].col_grid = col_grid
	self.maps[iter].height = height
	self.maps[iter].width = width
	self.maps[iter].t_wid = t_wid
	self.maps[iter].t_hgh = t_hgh
	
	self.maps[iter].viewport = MOAIViewport.new()
	self.maps[iter].viewport:setSize( 
		SCREEN_RESOLUTION_X-SCREEN_RESOLUTION_X*0.125, 
		SCREEN_RESOLUTION_Y-SCREEN_RESOLUTION_Y*0.125)
	self.maps[iter].viewport:setScale ( WORLD_RESOLUTION_X, -WORLD_RESOLUTION_Y )
	self.maps[iter].viewport:setOffset(-0.885, 0.885)
	self.maps[iter].layer = MOAILayer2D.new()
	self.maps[iter].layer:setViewport(self.maps[iter].viewport)
	self.maps[iter].layer:setCamera(Game.camera)
	
	-- render the layer
	Game:render_layer( self.maps[iter].layer )
	
	--[[
	
	local renderTable = MOAIRenderMgr.getRenderTable()
	
	if pos then 
		table.insert ( renderTable, pos, self.maps[iter].layer )
	else
		table.insert ( renderTable, self.maps[iter].layer )
	end

	MOAIRenderMgr.setRenderTable ( renderTable )
	
	]]
	
	self:path_update_grid( self.maps[iter] )
	
	Game:space_bg()
	Game:populateBackground()
	
	
	return self.maps[iter]

end

function MapManager:path_update_grid( map )

	if map then
		self.path:setGraph( map.col_grid )
	else
		print("ERROR: path_update_grid arg \"map\" invalid")
	end
	

end

function MapManager:map_thread_callback ( )

	local iter = #self.maps
	
	self:path_update_grid ( self.maps[iter] )

end


function MapManager:collision_grid ( grid )
	
	local width, height = grid:getSize()
	local col_grid = MOAIGrid.new()
	col_grid:setSize( width, height, TILE_SIZE, TILE_SIZE )

	for x = 1, width do
		for y = 1, height do
			local t = grid:getTile(x,y)
			if MapManager:isWalkable(t)	then
			
				col_grid:setTile(x,y,t)
			
			end
		
		end
	end
	
	return col_grid

end

function MapManager:collision_grids( grids )

	local col_grid = MOAIGrid.new()

	for i = 1, #grids do
		local width, height = grids[i]:getSize()
		
		col_grid:setSize( width, height, TILE_SIZE, TILE_SIZE )
		
		for x = 1, width do
			for y = 1, height do
				local t = grids[i]:getTile(x, y)
				if MapManager:isWalkable(t)	then
			
					col_grid:setTile(x,y,t)
					
					
				end
			
			end
			
			
			
		
		
		end		
	
	
	end
	
	return col_grid
	
	


end

function MapManager:isWalkable( type )


	local actions = {
		[FLOOR_TILE] = function() return true end,
		[DOOR_TILE] = function() return true end,
		[AIRLOCK_TILE] = function() return true end,
		[CONTROL_PANEL] = function() return true end,	
	}
	
	if actions[type] then
		return true
		
	else
	
		return false
	end

	
end

function MapManager:manual_grid( grid )

	self.mg_cache = grid
	
	

end


function MapManager:toMOAIGrid( grid )

	local m_grid = MOAIGrid.new()

	for y = 1, #grid do
		for x = 1, #grid[y] do
		
			m_grid:setTile(x, y, grid[y][x])
		
		end	
	end
	
	return m_grid


end

function MapManager:new_cell_auto_map(grid, height, width, t_wid, t_hgh)

	

	for y = 1, height do
		for x = 1, width do 
		
			local r = self.rng:random(100)
			
			if r < 40 then
				grid:setTile(x, y, WALL_TILE)
			else
				grid:setTile(x, y, FLOOR_TILE)
			end
			
		
		end
	end
	
	local iter1 = 5
	local iter2 = 3
	
	for i = 1, iter1 do
	
		for y = 1, height do
			for x = 1, width do
				local z = self:surrounding_walls(grid, x, y, 1, 1)
				local q = self:surrounding_walls(grid, x, y, 2, 2)
				if z > 5 then
					grid:setTile(x, y, WALL_TILE)				
				end
			
				if q < 2 then
					grid:setTile(x, y, WALL_TILE)
				end
				
			end
		
		end
	end

	for i = 1, iter2 do
		
		for y = 1, height do
			for x = 1, width do
			
				local z = self:surrounding_walls(grid,x,y,1,1)
				local q = self:surrounding_walls(grid, x, y, 2, 2 )
				
				if z > 5 then
					grid:setTile(x, y, WALL_TILE)
				end
				
				self:surrounding_diag(grid, x, y)
				
			end
		end
	
	end
	
	
	for y = 1, height do
		for x = 1, width do
		
			if y == 1 or x == 1 
				or x == width or y == height then
				
				grid:setTile(x, y, SPACE_TILE)
				
			end
			
			if y == 2 or x == 2 
				or x == width-1 or y == height-1 then
				local gt = grid:getTile(x,y)
				if gt ~= SPACE_TILE then
					
					grid:setTile(x, y, WALL_TILE)
					
				end
				if y == 2 then
				
					local gt2 = grid:getTile(x,y+1)
					
					if gt2 == SPACE_TILE then
						grid:setTile(x, y, SPACE_TILE)
					end
					
				end
				
				if x == 2 then
					
					local gt2 = grid:getTile(x+1,y)
					
					if gt2 == SPACE_TILE then
						grid:setTile(x, y, SPACE_TILE)
					end
				
				end
				
				if x == width-1 then
					
					local gt2 = grid:getTile(x-1,y)
					
					if gt2 == SPACE_TILE then
						grid:setTile(x, y, SPACE_TILE)
					end
				
				end
				
				if y == height-1 then
					local gt2 = grid:getTile(x,y+1)
					
					if gt2 == SPACE_TILE then
						grid:setTile(x, y, SPACE_TILE)
					end
				end
				
			end
			
			
		
		end
	
	end

	return grid

end

function MapManager:surrounding_diag(grid, x, y)
	
	if grid:getTile(x, y) == WALL_TILE then
		local ul = grid:getTile(x-1, y-1)
		local ur = grid:getTile(x+1, y-1)
		local ll = grid:getTile(x-1, y+1)
		local lr = grid:getTile(x+1, y+1)
		local l = grid:getTile(x-1, y)
		local r = grid:getTile(x+1, y)
		local u = grid:getTile(x, y-1)
		local lo = grid:getTile(x, y+1)
		
		if l == FLOOR_TILE and u == FLOOR_TILE and r == FLOOR_TILE then
		
			grid:setTile(x, y, FLOOR_TILE)
		end
		
		if l == FLOOR_TILE and lo == FLOOR_TILE  and r == FLOOR_TILE then
		
			grid:setTile(x, y, FLOOR_TILE)
		end
		
		if (ul == WALL_TILE or ul == SPACE_TILE)
			and ( ur == WALL_TILE or ur == SPACE_TILE )
			and ( ll == WALL_TILE or ll == SPACE_TILE )
			and ( lr == WALL_TILE or lr == SPACE_TILE )
			and ( l == WALL_TILE or l == SPACE_TILE )
			and ( r == WALL_TILE or r == SPACE_TILE )
			and ( u == WALL_TILE or u == SPACE_TILE )
			and ( lo == WALL_TILE or lo == SPACE_TILE) then
			
			grid:setTile(x,y, SPACE_TILE)
			
		end
	
		
	
	end

end

function MapManager:surrounding_walls(grid, x, y, distX, distY)

	local walls = 0
	
	if distX == 1 and distY == 1 then
	
		if grid:getTile(x-1, y-1) == WALL_TILE then
			walls = walls + 1
		end
		
		if grid:getTile(x-1, y) == WALL_TILE then
			walls = walls + 1
		end
		
		if grid:getTile(x-1, y+1) == WALL_TILE then
			walls = walls+1
		end
		
		if grid:getTile(x, y-1) == WALL_TILE then
			walls = walls + 1
		end
		
		if grid:getTile(x, y+1) == WALL_TILE then
			walls = walls + 1 
		end
		
		if grid:getTile(x+1, y) == WALL_TILE then
			walls = walls + 1			
		end
		
		if grid:getTile(x+1, y-1) == WALL_TILE then
			walls = walls+1
		end
		
		if grid:getTile(x+1, y+1) == WALL_TILE then
			walls = walls + 1
		end
	
	else
		local y2 = distY - y
		local x2 = distX - x
		for y1 = 1, distY do
			for x1 = 1, distX do
				
				local v = grid:getTile(x+x1-1, y+y1-1)
				local v2 = grid:getTile(x-x1, y-y1)
				
				if v  == WALL_TILE then
					
					walls = walls + 1
				
				end
				
				if v2 == WALL_TILE then
				
					walls = walls + 1
					
				end
				
			end
		end
	end
	
	--print("walls : " .. walls)

	return walls

end

return MapManager